# Built-In Example AI

# Title: LieorlieTurtle
# Author: Lieorlie
# Version: 1.1.5
# Date:5/6/2021

import random
import game.tcturtle
import math

class CombatTurtle(game.tcturtle.TurtleParent):
    """Wanderer combat turtle.

    Wanders around randomly until it gets close enough to the opponent, after
    which it directly pursues them.
    """

    # -------------------------------------------------------------------------


    def class_name():
        """CombatTurtle.class_name() -> str
        Static method to return the name of the Combat Turtle AI.
        """

        return "ct_guilaidui"

    # -------------------------------------------------------------------------

    def class_desc():
        """CombatTurtle.class_desc() -> str
        Static method to return a description of the Combat Turtle AI.
        """

        return "This turtle is incredibal !!!."

    # -------------------------------------------------------------------------

    def class_shape():
        """CombatTurtle.class_shape() -> (int or tuple)
        Static method to define the Combat Turtle's shape image.

        The return value can be either an integer or a tuple of tuples.

        Returning an integer index selects one of the following preset shapes:
            0 -- arrowhead (also default in case of unrecognized index)
            1 -- turtle
            2 -- plow
            3 -- triangle
            4 -- kite
            5 -- pentagon
            6 -- hexagon
            7 -- star

        A custom shape can be defined by returning a tuple of the form
        (radius, angle), where radius is a tuple of radii and angle is a tuple
        of angles (in radians) describing the polar coordinates of a polygon's
        vertices. The shape coordinates should be given for a turtle facing
        east.
        """

        return 0

    # =========================================================================

    def setup(self):
        """CombatTurtle.setup() -> None
        Initialization code for Combat Turtle.
        """

        # Define pursuit cutoff distance
        # Define pursuit cutoff distance
        self.pursuit_range = 0.75 * self.missile_range

        self.SniperDistance = 320
        self.MaxDistance = 500

        self.flag = 0  # 躲子弹模式的开关标识
        self.flag_run = 0  # 遇到障碍物开始跑模式的开关标识
        self.shootheading = 0  # 对方开火时的朝向
        self.runheading = 0  # 记录碰到墙时的朝向
        self.runtime = 0  # 碰到墙后开始跑的时间
        self.scale = 0

    # -------------------------------------------------------------------------

    def step(self):
        #通过捕获对方射击冷却，得到对方开枪时的角度
        if self.other_cooldown == 59:
            self.shootheading = self.other_heading
            self.ChangArea()
            self.flag = 1  # 开启躲子弹范围乱窜

        # 对方枪口冷却且子弹必定爆炸的时
        elif self.other_cooldown <= 40:
            self.flag = 0  # 关闭乱窜

        else:
            pass

        if self.CannotMove():  # 如果不能动了，或者有障碍物，就开始跑
            self.flag_run = 1
            self.runheading = self.heading
            self.runtime = 10 #碰障碍物逃离时间

        if not self.CannotMove() and self.runtime <= 0:
            self.flag_run = 0


        if self.can_shoot and self.line_of_sight():
            if self.MaxDistance >= self.distance() >= self.SniperDistance:
                self.SniperMode()

            elif self.distance() >= self.MaxDistance:
                self.CloseMode()

            elif (self.distance() <= self.pursuit_range):


                if 5 < self.other_cooldown < 40:
                    self.turn_towards()
                    self.forward()
                    if self.AimTarget() and self.line_of_sight():
                        self.Shoting()
                else :
                    self.Avoid()


            else:
                # print("ggg")
                self.FleeMode()


        else:
            self.Avoid()

    #狙击模式，开局时采用远射战术
    def SniperMode(self):
        self.turn_towards()

        if self.Isdanger() or self.other_cooldown > 30:
            self.Avoid()

        elif not self.Isdanger():
            if self.AimTarget():
                self.Shoting()

        else:
            self.Avoid()

    #逃离模式，如果不是太近又低于射击模式距离时使用
    def FleeMode(self):
        # self.turn_towards()

        # if self.Isdanger():
        #     self.BackAttack()
        #
        # else:
        if self.other_cooldown > 15:
            self.Avoid()
        else:
            self.turn_towards()
            self.backward()
            if self.AimTarget() and self.line_of_sight():
                self.Shoting()

    #超远距离射击模式，适当拉近距离
    def CloseMode(self):
        self.turn_towards()
        if self.AimTarget() and self.line_of_sight():
            self.Shoting()
        else:
            self.turn_towards()
            self.forward()


    #计算两龟之间角度
    def GetSlope(self):
        (dx, dy) = self.relative_position()
        return int(math.atan2(dy, dx) * (180 / math.pi))

    #判断对方是否瞄着我方且可以射击
    def Isdanger(self):
        if (170 <= abs(self.GetSlope() + self.other_heading) <= 190) and self.other_can_shoot:
            return True
        return False

    #判断我方是否正好瞄着对方且可以射击
    def AimTarget(self):
        if (0 <= abs(self.GetSlope() + self.heading) <= 8) and self.can_shoot:
            return True
        return False


    #射击
    def Shoting(self):
        if (self.can_shoot and abs(self.relative_heading_towards()) <= 8 and
                self.line_of_sight() and self.distance() > 2*self.missile_radius):
            self.shoot()


    #躲避子弹:通过判断对方发射子弹的方向，朝着射击线上垂直90度方向移动
    def Avoid(self):
        if self.flag and not self.flag_run:
            self.turn_towards(random.randrange(self.scale - 10, self.scale + 10))
            self.forward()

        elif self.flag_run:
            self.backward()
            self.left()
            self.runtime -= 1

        else:
            self.turn_towards(random.randrange(-179, 181))
            self.forward()

    # 改变随机参数，配合躲避子弹
    def ChangArea(self):
        if self.shootheading > 0:
            self.scale = (self.shootheading + 90) % 180
            dx, dy = self.PredictCoordinate(self.scale)
            if self.CalDistance(dx, dy):
                self.scale = (self.shootheading - 90) % 180

        else:
            self.scale = self.shootheading + 90
            dx, dy = self.PredictCoordinate(self.scale)
            if self.CalDistance(dx, dy):
                self.scale = (self.shootheading - 90)
        # print("{}|{}".format(self.shootheading, self.flag))

    # 预测下一时刻坐标
    def PredictCoordinate(self, cur_heading=None):
        if cur_heading == None:
            cur_heading = self.heading

        dy = int(4 * math.sin(cur_heading * (math.pi / 180)))
        dx = int(4 * math.cos(cur_heading * (math.pi / 180)))

        return self.x + dx, self.y - dy

    def CalDistance(self, dx=None, dy=None):
        if dx == None or dy == None:
            dx = self.x
            dy = self.y

        dis_x = self.other_x - dx
        dis_y = self.other_y - dy
        dis = math.sqrt((dis_x ** 2) + (dis_y ** 2))
        if dis < self.distance():
            return True  # 判断为靠近弹道

        else:
            return False  # 判断为远离弹道

    def CannotMove(self):
        dx, dy = self.PredictCoordinate()
        if not self.free_space((dx, dy)):
            return True

        return False







    # =========================================================================



